package com.gxuwz.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.log4j.Logger;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;

import com.gxuwz.business.entity.SysRight;
import com.gxuwz.business.entity.SysRole;
import com.gxuwz.business.service.ISysRightService;
import com.gxuwz.business.service.ISysRoleService;


/**
 * 
 * <p>
 * 功能描述：资源源数据定义，将所有的资源和权限对应关系建立起来，即定义某一资源可以被哪些角色访问
 * 
 * @author Timo
 * @date:2018年5月20日
 */
public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
	
	private final Logger log = Logger.getLogger(getClass());
	
	// resourceMap用static声明了，为了避免用户每请求一次都要去数据库读取资源、权限，这里只读取一次，将它保存起来
	// 保存资源和权限的对应关系 key-资源  value-权限
	private Map<String, Collection<ConfigAttribute>> resourceMap = null;
	
	private ISysRightService rightService;
	
	public MySecurityMetadataSource(){}
	public MySecurityMetadataSource(ISysRightService rightService) {
		this.rightService = rightService;
		loadResourceDefine();
	}

	private void loadResourceDefine() {
		log.info("更新权限资源");
		if(resourceMap==null){
		    resourceMap = new ConcurrentHashMap<String, Collection<ConfigAttribute>>();
		}else{
			resourceMap.clear();
		}
		//加载数据库所有权限
		//构建：资源路径-资源id集合
		//（还未与角色关联）
		List<SysRight> rights = rightService.getRightAll();
		for (SysRight right : rights) {
			// 将权限id配置到security中
			ConfigAttribute authority = new SecurityConfig(right.getRightId());
			// 查找权限对应的资源
			String url = right.getResourcePath();
				// 如果同一url有多个角色可以访问，那么把这些角色都添加到对应的键(url)对的值(Collection<ConfigAttribute>)里面
				if (resourceMap.containsKey(url)) {
					Collection<ConfigAttribute> value = resourceMap.get(url);
					value.add(authority);
					//同一资源路径对应多个权限id
					resourceMap.put(url, value);
				} else {
					List<ConfigAttribute> value = new ArrayList<ConfigAttribute>();
					value.add(authority);
					resourceMap.put(url, value);
				}
		}
	}

	//这个方法在url请求时才会调用，服务器启动时不会执行这个方法，前提是需要在<http>标签内设置  <custom-filter>标签
	//根据请求url返回资源id
	@Override
	public Collection<ConfigAttribute> getAttributes(Object object)
			throws IllegalArgumentException {
		//更新权限信息
		loadResourceDefine();
		//获取用户请求的url
		String url = ((FilterInvocation) object).getRequestUrl();
		log.info("请求url： "+url);
		for (Map.Entry<String, Collection<ConfigAttribute>> entry : resourceMap.entrySet()) {
			// 如果请求的url与数据库中的权限对应的url相等，返回该权限，否则返回一个null;
			if (url.contains(entry.getKey())) {
				return entry.getValue();
			}
		}
		return null;
	}

	@Override
	public Collection<ConfigAttribute> getAllConfigAttributes() {
		return null;
	}

	@Override
	public boolean supports(Class<?> clazz) {
		return true;
	}

}
